package experiment;

import heuristics.AmbitiousStudentHeuristic;
import heuristics.IHeuristic;
import heuristics.LazyStudentHeuristic;
import heuristics.WorkingStudentHeuristic;

import java.io.IOException;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import log.Log;
import Entities.Calendar;
import Entities.CoursesConfiguration;
import algorithms.RandomRestartHC;

public class RandomRestartExperiment extends BaseExperiment {
	final static String[] logLabels = {"Heuristic", "Size of Random Calendar", 
		"Average Heuristic Value", "Average Number of Heuristic Calls to Best"};
	final static int numberOfHeuristicCalls = 100000;
	final static int[] sizeOfRandomCalendar = {2,6,7,10,15,20};
	final static String logPath = "experiments_output/RandomRestartExperimentResult.csv";
	static List<IHeuristic> heuristics;
	static RandomRestartHC algo;
	static Log log;
	
	public RandomRestartExperiment()
	{
		try {
			log = new Log(logPath);
			log.writeLabels(logLabels);
			setCourseConfigurations("coursesConfigurations");
		} catch (IOException e) {
			e.printStackTrace();
		}

		heuristics = new LinkedList<IHeuristic>();
		heuristics.add(new LazyStudentHeuristic());
		heuristics.add(new AmbitiousStudentHeuristic());
		heuristics.add(new WorkingStudentHeuristic());
		
		algo = new RandomRestartHC();
		algo.setMaxOfHeuristicCalls(numberOfHeuristicCalls);
	}
	
	@Override
	public void Execute() {
		System.out.println("Experiment Started: " + getDateTime());
		
		Calendar currCalendar;
		double averageHeuristicValue = 0;
		int averageNumberOfHeuristicCallsToBest = 0;

		for (IHeuristic iHeuristic : heuristics) {
			Calendar.setHeuristic(iHeuristic);
			for (int i = 0; i < sizeOfRandomCalendar.length; i++) {
				RandomRestartHC.setSizeOfRandomCalendar(sizeOfRandomCalendar[i]);
				averageHeuristicValue = 0;
				averageNumberOfHeuristicCallsToBest = 0;
				for (CoursesConfiguration config : courseConfigurations) {
					Calendar.init(config.getCoursesConfiguration());
					for (int j = 0; j < NUMBER_OF_REPETED_EXECUTIONS; j++) {
						algo.reset(); // reset variables in algorithm
						currCalendar = algo.searchLocal();
						averageHeuristicValue += currCalendar.getHeuristicValue();
						averageNumberOfHeuristicCallsToBest += algo.getNumberOfHeuristicCallsToBest();
					}
				}
				averageHeuristicValue /= (double)(NUMBER_OF_REPETED_EXECUTIONS*courseConfigurations.size());
				averageNumberOfHeuristicCallsToBest /= (double)(NUMBER_OF_REPETED_EXECUTIONS*courseConfigurations.size());
				WriteToLog(iHeuristic.toString(), sizeOfRandomCalendar[i], 
							averageHeuristicValue, averageNumberOfHeuristicCallsToBest);
			}
		}
		
		
		System.out.println("Experiment Ended: " + getDateTime());
		
		try {
			log.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	private void WriteToLog(String heuristicName, int sizeOfRandomCalendar,
			double averageHeuristicValue, int averageNumberOfHeuriticCallsToBest) {
		HashMap<String, String> data = new HashMap<String, String>();
		data.put("Heuristic", heuristicName);
		data.put("Size of Random Calendar", String.valueOf(sizeOfRandomCalendar));
		data.put("Average Heuristic Value", String.valueOf(averageHeuristicValue));
		data.put("Average Number of Heuristic Calls to Best", String.valueOf(averageNumberOfHeuriticCallsToBest));
		try {
			log.writeData(data);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
	


}
